package com.ljk.configuration.aspectconfig;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

/**
 * <p>
 * {@link Aspect} (代表将这个类用做aop类)
 * <p>
 * {@link Component} (代表将这个类注册进spring中)
 * <p>
 * {@link EnableAspectJAutoProxy}(这个是启用注解配置aop功能的注解,也可以在xml中配置,配一个就行 proxy-target-class 为true代表cglib代理,false使用jdk代理  default:false)
 *
 * @author leng
 * @date 2020/6/20 8:12
 */
@Aspect
@Component
public class LogAspects {
    /**
     * 要扫描的包格式,可自定义
     * execution(* com.ljk.controller.ExampleController.*(..))
     * [*]代表忽略方法的修饰符和返回类型
     * [com.ljk.controller.]代表的是包名,可以用*忽略
     * [**]代表的是忽略子包名和类名
     * [*(..)]代表的是方法名和方法的参数[..]代表的是忽略参数限制
     */
    private final String SCAN = "execution(* com.ljk.controller.study.**.*(..))";

    /**
     * 前置通知  ,参数可为空
     *
     * @param joinPoint 拿到被拦截的方法的名称
     */
    @Before(value = SCAN)
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("前置通知");
    }

    /**
     * 环绕通知 ,参数可为空
     * ProceedingJoinPoint 是 joinPoint的子类,暴露出 proceed方法
     * 调用时执行的就是被拦截的方法
     *
     * @param point
     * @throws Throwable
     */
    @Around(value = SCAN)
    public void logAround(ProceedingJoinPoint point) throws Throwable {
        System.out.println("********************环绕通知前方法");
        long timeMillis = System.currentTimeMillis();
        try {
            point.proceed();
        } catch (Throwable e) {
            throw e;
        } finally {
            System.out.printf("********************环绕通知后方法,代理方法的时长:%s ms\n", System.currentTimeMillis() - timeMillis);
        }

    }

    /**
     * 异常通知
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = SCAN, throwing = "e")
    public void logThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.printf("异常通知:%s\n", e.getMessage());
        System.err.println("异常通知");
    }

    /**
     * 后置通知
     */
    @After(value = SCAN)
    public void logAfter() {
        System.out.println("后置通知");
    }

    /**
     * 不常用,可以忽略 将IDeclareParentsImpl 注入ExampleController中
     * <p>
     * {@link DeclareParents} 用于定义引介通知，相当于IntroductionInterceptor（不要求掌握）。
     */
    @DeclareParents(value = "com.ljk.controller.study.ExampleController", defaultImpl = IDeclareParentsImpl.class)
    private IDeclareParents declareParents;
}
